﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Linq;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Windows.Forms;

namespace CDDocumentExtractor
{
    public partial class frmManuFileProcessor : DevExpress.XtraEditors.XtraForm, ITracer
    {
        private List<ManuFile> FilesToImport;

        public frmManuFileProcessor()
        {
            InitializeComponent();
        }

        private void frmManuFileProcessor_Load(object sender, EventArgs e)
        {

            txtFolderName.Text = DateTime.Now.AddYears(-50).ToString("MMyyyy");

            lkupCourts.Properties.ReadOnly = false;
            var dt = Program.GetCourtsJurisdictionData();
            lkupCourts.Properties.DataSource = dt;
            lkupCourts.Size = lkupCourts.PreferredSize;

            if (dt.Rows.Count > 0)
            {
                lkupCourts.ItemIndex = 0;
            }
            FilesToImport = new List<ManuFile>();
        }

        //private void GenerateInfoOneCitationNos()
        //{
        //    var list = from f in FilesToImport
        //               orderby f.Year ascending,f.DecidedOn descending
        //               select f;

        //    //Citation no would be generated in date order
        //    var docList = list.ToList();

        //   using (var con =
        //       new System.Data.SqlClient.SqlConnection(
        //           System.Configuration.ConfigurationManager.ConnectionStrings[
        //               "CDDocumentExtractor.Properties.Settings.InfoOneConnectionString"].ConnectionString))
        //   {
        //        con.Open();
        //        var com = con.CreateCommand();
        //        com.CommandType = System.Data.CommandType.Text; 

        //        foreach (var manuFile in docList)
        //        {
        //            try
        //            {
        //                manuFile.Error += "Generating Citation No." + Environment.NewLine;
        //                com.CommandText =
        //                    "SELECT COUNT(DocumentId) from DocumentMeta " +
        //                    "WHERE " +
        //                    "DocumentType=1 " +
        //                    " AND Year(DocumentIssueDate)=" + manuFile.Year +
        //                    " AND IsNull(InfoOneCitation,'')=''";

        //                var result = com.ExecuteScalar() ?? 0;

        //                int uniqueNo = Convert.ToInt32(result);
        //                uniqueNo++;

        //                var newCitationNo =
        //                    "InfoOne/" + Program.CourtName + "/" + uniqueNo + "/" + manuFile.Year.ToString();

        //                com.CommandText = "UPDATE DocumentMeta SET InfoOneCitation = '" + newCitationNo +
        //                                  "' Where DocumentID = " +
        //                                  manuFile.InfoOneID;
        //                com.ExecuteNonQuery();

        //                manuFile.InfoOneCitationNo = newCitationNo;
        //                manuFile.Status = "Done";
        //            }catch(Exception ex)
        //            {
        //                manuFile.Status = "Error";
        //                manuFile.Error += ex.Message +"****" + ex.StackTrace + Environment.NewLine;
        //            }
        //            finally
        //            {
        //                var lvi = new ListViewItem();
        //                lvi.Text = manuFile.ManuCitationNo;
        //                lvi.SubItems.Add(manuFile.Status);
        //                lvi.SubItems.Add(manuFile.InfoOneCitationNo);
        //                lvCitationNo.Items.Add(lvi);
        //                Application.DoEvents();
        //            }

        //        }
        //    }
        //}

        private void StartImportingFiles()
        {
            Directory.CreateDirectory(WebUtility.ArchieveFolder);
            var allfiles = Directory.GetFiles(WebUtility.SourceFolder, "MANU*.txt").ToList();

            int i = 0;
            foreach (var file in allfiles)
            {
                var mf = new ManuFile(i, file);
                FilesToImport.Add(mf);
                i++;
            }

            //Sort the list by year first and then by serial no
            FilesToImport = FilesToImport.OrderBy(f => f.Year).ThenBy(f2 => f2.SerialNo).ToList();
            txtLog.Text = "";

            foreach (var item in FilesToImport)
            {
                var data = File.ReadAllText(item.FileName);
                try
                {
                    item.Error += "Initialising class..." + Environment.NewLine;
                    var cd = new CaseDocument(data);
                    item.Error += "Class Initialised" + Environment.NewLine;
                    try
                    {
                        item.Error += "Saving now..." + Environment.NewLine;
                        bool result = cd.SaveBySP();
                        item.Error += "Save Completed" + Environment.NewLine;
                        item.Status = "Completed";

                        if (result)
                        {
                            //Move the file to a different name
                            File.Move(item.FileName, Path.Combine(WebUtility.ArchieveFolder, Path.GetFileName(item.FileName)));

                            //Write Updated File at this location with removed information
                            //This is only required if Link parsing should be done
                            //If resulting file doesn't contatins any link this step is not required
                            if (cd.LinkParsingRequired)
                            {
                                item.Error += "Moving to Processed for Links Processing" + Environment.NewLine;
                                File.WriteAllText(
                                    Path.Combine(WebUtility.SourceFolder, "PROCESSED_" + Path.GetFileName(item.FileName)),
                                    cd.InfoOneDocumentData);

                                item.Status = "Links Pending";
                            }
                        }
                    }
                    catch (Exception ex)
                    {
                        item.Error += cd.CitingRefData_XML + Environment.NewLine;
                        item.Error += ex.Message + "***" + ex.StackTrace + Environment.NewLine;
                        item.Status = "Error";
                        //Move the file to a different name
                        if (File.Exists(Path.Combine(WebUtility.ArchieveFolder, "Error_" + Path.GetFileName(item.FileName))))
                            File.Delete(Path.Combine(WebUtility.ArchieveFolder, "Error_" + Path.GetFileName(item.FileName)));

                        File.Move(item.FileName, Path.Combine(WebUtility.ArchieveFolder, "Error_" + Path.GetFileName(item.FileName)));
                    }
                    finally
                    {
                        item.InfoOneID = Convert.ToInt32(cd._InfoOneID);
                        item.InfoOneCitationNo = cd.InfoOneCitationNo;
                        item.DecidedOn = cd._DecidedOn;

                        item.InfoOne_SectionID = cd._DocumentSectionID;
                        item.Pdf_File_Path = cd.PDFFilePath;
                        item.Doc_File_Path = cd.DOCXFilePath;
                        item.Html_File_Path = cd.HTMLFilePath;

                        item.IsPublished = cd.LinkParsingRequired;
                    }
                }
                catch (Exception ex1)
                {
                    item.Error += ex1.Message + "***" + ex1.StackTrace + Environment.NewLine;
                    item.Status = "Error";
                    //Console.WriteLine(ex1.Message + "***" + ex1.StackTrace);
                }

                this.WriteLine("Processing ... " + item.ManuCitationNo);
                this.WriteLine(item.Status);
                this.WriteLine(item.Error);
                this.WriteLine("");

                Application.DoEvents();
            }

            this.WriteLine("Processing Links in the Documents");
            ParseLinksInDocument();
            this.WriteLine("Done... Processing Links in the Documents");

            //this.WriteLine("Creating Document PDF files from Section Files");
            //Common.CreateDocumentPDFs(Path.Combine(WebUtility.DocumentsFolder,
            //                                       "PublishedDocs/" + txtFolderName.Text),this);
            //this.WriteLine("Done... Creating Document PDF files from Section Files");

            var obj = new ObjectToSerialize { Files = FilesToImport };

            File.WriteAllText(Path.Combine(Application.StartupPath, Program.Juridiction + "_" + Program.CourtNameId + "_" + DateTime.Now.ToString("yyyyMMddHHmmss") + "_ImportedData.html"), obj.ToHtml());
            //this.SerializeObject(Path.Combine(Application.StartupPath,DateTime.Now.ToString("yyyyMMddHHmmss") + "_ImportedData.dat"),obj);
            MessageBox.Show("Done...");
        }

        void cd_MessageSent(string msg)
        {
            WriteLine(msg);
        }

        public void SerializeObject(string filename, ObjectToSerialize objectToSerialize)
        {
            Stream stream = File.Open(filename, FileMode.Create);
            var bFormatter = new BinaryFormatter();
            bFormatter.Serialize(stream, objectToSerialize);
            stream.Close();
        }

        public void WriteLine(string msg)
        {
            this.txtLog.AppendText(msg + Environment.NewLine + Environment.NewLine);
        }

        public ObjectToSerialize DeSerializeObject(string filename)
        {
            Stream stream = File.Open(filename, FileMode.Open);
            var bFormatter = new BinaryFormatter();
            var objectToSerialize = (ObjectToSerialize)bFormatter.Deserialize(stream);
            stream.Close();
            return objectToSerialize;
        }

        private void simpleButton1_Click(object sender, EventArgs e)
        {
            var res = MessageBox.Show("Are you sure you want to start. You may recheck the settings if you want?",
                                      "Confirmation", MessageBoxButtons.YesNo, MessageBoxIcon.Question);

            //return if user said no
            if (res == DialogResult.No)
                return;

            var row = lkupCourts.GetSelectedDataRow() as DataRowView;

            if (row == null)
            {
                MessageBox.Show("Nothing Selected...");
                return;
            }
            //MessageBox.Show(row[0] + "**" + row[1] + "**" + row[2] + "**" + row[3] + "**" + row[4]);

            Program.Juridiction = Convert.ToString(row[0]);
            Program.CourtNameId = Convert.ToString(row[3]);
            Program.CourtName = Convert.ToString(row[4]);
            
            StartImportingFiles();
        }

        private void listView1_SelectedIndexChanged(object sender, EventArgs e)
        {

        }

        /// <summary>
        /// This method will process document to update all the links
        /// All links will be replaced by InfoOne Links
        /// </summary>
        public void ParseLinksInDocument()
        {
            string RegEx_ManuID = "MANU\\x2F\\w*\\x2F\\d*\\x2F\\d{4}";
            string manuID = "";
            var rxManuId = new System.Text.RegularExpressions.Regex(RegEx_ManuID,
                                             System.Text.RegularExpressions.RegexOptions.IgnoreCase |
                                             System.Text.RegularExpressions.RegexOptions.Singleline);

            var manuIds = new List<string>();
            string mainDocumentID = "";

            using (var db = new I1DBModelDataContext())
            {
                var dirInfo = new DirectoryInfo(WebUtility.SourceFolder);
                var searchedDocs = (from f in dirInfo.GetFiles("PROCESSED_*.*")
                                   orderby f.LastWriteTime
                                   select f.FullName).ToList();

                //var searchedDocs = Directory.GetFiles(WebUtility.SourceFolder, "PROCESSED_*.*").ToList();
                if (searchedDocs.Count <= 0)
                    return;

                Console.WriteLine("Working on Total : " + searchedDocs.Count);
                //Process all documents
                foreach (var document in searchedDocs)
                {
                    manuIds.Clear();
                    mainDocumentID = "";

                    manuID = Path.GetFileNameWithoutExtension(document).Replace("PROCESSED_", "").Replace("_",
                                                                                                          "/");
                    manuIds.Add(manuID);
                    //Variable used to check if all the links are processed or not.
                    var processingComplete = true;
                    try
                    {
                            Console.WriteLine("Processing Links in : " + document);

                            string documentData = File.ReadAllText(document);
                            var links = Common.GetTags("a", documentData);
                            var linkEntities = new List<ManuLinkEntity>();

                            //If atleast one manu link found
                            if (links.Count > 0 && links.Count(lnk => lnk.Contains("MANU")) > 0)
                            {
                                //Code below will remove any extra text from the link text and provide only manu ids
                                foreach (string t in links)
                                {
                                    if (t.Contains("MANU"))
                                    {
                                        var link = new ManuLinkEntity();
                                        linkEntities.Add(link);
                                        link.LinkTag = t;
                                        //Link Text
                                        link.LinkText = System.Text.RegularExpressions.Regex.Replace(link.LinkTag,
                                                                                                     "<.*?>",
                                                                                                     string.Empty);
                                        //Manu ID
                                        link.ManuCitation = rxManuId.Match(link.LinkTag).Value.Trim();
                                        manuIds.Add(link.ManuCitation);
                                    }
                                }

                                var searchedData = (from dmd in db.DocumentMetas
                                                    where manuIds.Contains(dmd.ManupatraCitation)
                                                    select new
                                                               {
                                                                   ManuID = dmd.ManupatraCitation, dmd.DocumentID, dmd.InfoOneCitation
                                                               }).ToList();
                                if (searchedData.Count > 0)
                                {
                                    var mainDocument = searchedData.Find(sd => sd.ManuID.Equals(manuID));
                                    if (mainDocument != null)
                                    {
                                        mainDocumentID = mainDocument.DocumentID.ToString(CultureInfo.InvariantCulture);

                                        foreach (var manuLinkEntity in linkEntities)
                                        {
                                            var itemData =
                                                searchedData.Find(
                                                    sd => sd.ManuID.Equals(manuLinkEntity.ManuCitation));
                                            if (itemData != null)
                                            {
                                                //Create Relation for this document
                                                db.DocumentRelations.InsertOnSubmit(entity: new DocumentRelation()
                                                                      {
                                                                          DocumentID = Convert.ToInt32(mainDocumentID),
                                                                          Createdby = 1,
                                                                          CreatedDate = DateTime.Now,
                                                                          RelatedDocumentID = itemData.DocumentID,
                                                                          IsPublished = true
                                                                      });

                                                //Get Linked Document Info
                                                manuLinkEntity.InfoOneID = itemData.DocumentID;
                                                manuLinkEntity.InfoOneCitation = itemData.InfoOneCitation;

                                                //Replace Manu IDs from Link Text with InfoOne Citation
                                                //link.LinkText = rxManuID.Replace(link.LinkText, link.InfoOneCitation);
                                                manuLinkEntity.LinkText = rxManuId.Replace(manuLinkEntity.LinkText,
                                                                                 "<a href='http://www.infooneplus.com/documentviewer.aspx?id=" +
                                                                                 manuLinkEntity.InfoOneID + "'>" +
                                                                                 manuLinkEntity.InfoOneCitation + "</a>");

                                                documentData = documentData.Replace(manuLinkEntity.LinkTag, manuLinkEntity.LinkText);
                                            }
                                            else
                                            {
                                                processingComplete = false;  //something seems pending here
                                            }
                                        }
                                        db.SubmitChanges(ConflictMode.ContinueOnConflict);
                                    }
                                }
                            }

                            //Update Contents of HTML File first
                            File.WriteAllText(document, documentData);

                            var path = (from dm in db.DocumentMasters
                                        where dm.DocumentID.Equals(mainDocumentID)
                                        select dm.Path).FirstOrDefault();

                            if (!string.IsNullOrEmpty(path))
                            {
                                string htmlPath =
                                    Path.Combine(WebUtility.DocumentsFolder.Replace("-main", ""),
                                                 path);

                                //Generating Files
                                Common.TryDelete(htmlPath);

                                if (!Directory.Exists(Path.GetDirectoryName(htmlPath)))
                                    Directory.CreateDirectory(Path.GetDirectoryName(htmlPath));

                                File.WriteAllText(htmlPath, documentData);

                                var doc = new Aspose.Words.Document(htmlPath);
                                doc.ViewOptions.ViewType = Aspose.Words.Settings.ViewType.PageLayout;

                                foreach (Aspose.Words.Section item in doc.Sections)
                                {
                                    foreach (Aspose.Words.Paragraph paras in item.Body.Paragraphs)
                                    {
                                        paras.ParagraphFormat.Alignment =
                                            Aspose.Words.ParagraphAlignment.Justify;
                                        paras.ParagraphFormat.Style.Font.Name = "Arial";
                                    }
                                }

                                string docxPath = Path.Combine(WebUtility.DocumentsFolder, path.Replace(".htm", ".docx"));
                                string pdfPath = Path.Combine(WebUtility.DocumentsFolder, path.Replace(".htm", ".pdf"));

                                Directory.CreateDirectory(Path.GetDirectoryName(docxPath));
                                Directory.CreateDirectory(Path.GetDirectoryName(pdfPath));

                                //Save to Docx
                                Common.TryDelete(docxPath);
                                doc.Save(docxPath, Aspose.Words.SaveFormat.Docx);

                                //Save the PDF
                                Common.TryDelete(pdfPath);
                                doc.Save(pdfPath, Aspose.Words.SaveFormat.Pdf);
                            }

                            //Publish Document if everything went well
                            string strUpdateQuery = "UPDATE DocumentMaster SET IsPublished=1 Where DocumentID=" + mainDocumentID;
                            if (processingComplete && db.ExecuteCommand(strUpdateQuery) > 0)
                            {
                                string newFilePath = Path.Combine(WebUtility.ArchieveFolder,
                                                                  manuID.Replace('/', '_') + ".txt");
                                Common.TryDelete(newFilePath);

                                //Write Updated Text into File
                                File.Move(document,newFilePath);
                            }
                    }
                    catch (Exception ex)
                    {
                        if (this != null)
                        {
                            this.WriteLine(document);
                            this.WriteLine("*********************************************");
                            this.WriteLine(ex.Message);
                            this.WriteLine("*********************************************");
                            this.WriteLine(ex.StackTrace);
                        }
                    }
                }
            }
        }
    }

    [Serializable]
    public class ObjectToSerialize
    {
        private List<ManuFile> files;

        public List<ManuFile> Files
        {
            get { return this.files; }
            set { this.files = value; }
        }

        public ObjectToSerialize()
        {
        }


        public string ToHtml()
        {

            var tabData = "<html><head></head><body>";
            tabData += "<Table border='1'>";

            tabData += "<tr>";

            tabData += "<th>ID</th>";
            tabData += "<th>FileName</th>";
            tabData += "<th>Status</th>";
            tabData += "<th>Error</th>";

            tabData += "<th>Year</th>";
            tabData += "<th>SerialNo</th>";
            tabData += "<th>CourtCode</th>";
            tabData += "<th>ManuCitationNo</th>";
            tabData += "<th>InfoOneID</th>";
            tabData += "<th>InfoOneCitationNo</th>";

            tabData += "<td>DecidedOn</td>";
            tabData += "</tr>";
            foreach (var manuFile in Files)
            {
                tabData += "<tr>";

                tabData += "<td valign='Top'>" + manuFile.ID + "</td>";
                tabData += "<td valign='Top'>" + manuFile.FileName + "</td>";
                tabData += "<td valign='Top'>" + manuFile.Status + "</td>";
                tabData += "<td valign='Top'>" + manuFile.Error.Replace(Environment.NewLine, "<br><br>") + "</td>";

                tabData += "<td valign='Top'>" + manuFile.Year + "</td>";
                tabData += "<td valign='Top'>" + manuFile.SerialNo + "</td>";
                tabData += "<td valign='Top'>" + manuFile.CourtCode + "</td>";
                tabData += "<td valign='Top'>" + manuFile.ManuCitationNo + "</td>";
                tabData += "<td valign='Top'>" + manuFile.InfoOneID + "</td>";
                tabData += "<td valign='Top'>" + manuFile.InfoOneCitationNo + "</td>";

                tabData += "<td valign='Top'>" + manuFile.DecidedOn + "</td>";
                tabData += "</tr>";
            }

            tabData += "</Table>";
            tabData += "</Body>";
            tabData += "</html>";

            return tabData;
        }





    }

    [Serializable]
    public class ManuFile
    {
        public int ID;
        public string FileName;
        public int Year;
        public int SerialNo;
        public string Status;
        public string CourtCode;

        public string ManuCitationNo;
        public int InfoOneID;
        public int InfoOne_SectionID;

        public string InfoOneCitationNo;
        public string InfoOneCourtCode;

        public DateTime DecidedOn;

        public string Error;

        public string Doc_File_Path;
        public string Pdf_File_Path;
        public string Html_File_Path;

        public bool IsPublished = false;

        public ManuFile(int id, string fileName)
        {
            try
            {
                var nameWithoutExtension = Path.GetFileNameWithoutExtension(fileName);
                if (nameWithoutExtension != null)
                {
                    var parts = nameWithoutExtension.Split('_');
                    ID = id;
                    Status = "Pending...";

                    CourtCode = parts[1];
                    SerialNo = Convert.ToInt32(parts[2]);
                    Year = Convert.ToInt32(parts[3]);
                }

                FileName = fileName;
                var fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileName);
                if (fileNameWithoutExtension != null)
                    ManuCitationNo = fileNameWithoutExtension.Replace('_', '/');

                InfoOneID = 0;
                InfoOne_SectionID = 0;
                InfoOneCitationNo = "";
                InfoOneCourtCode = "";
                DecidedOn = DateTime.MinValue;
                Error = "";

                Doc_File_Path = string.Empty;
                Pdf_File_Path = string.Empty;
                Html_File_Path = string.Empty;
            }
            catch (Exception ex)
            {
                MessageBox.Show(fileName + Environment.NewLine + ex.Message);
                throw;
            }
        }
    }

}